/**
 * 
 */
package controller.xml;

import java.io.File;

import model.cnf.CNF;
import model.preprocessor.PreProcessorFactory;
import model.session.CNFUse;
import model.session.CNFUseStatus;
import model.session.PreprocessorExecutionBlock;
import model.session.SessionBlock;
import model.session.SolverExecutionBlock;
import model.solver.SolverFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

/**
 * 
 * Use to parse a {@link CNFUse} in the exported session in XML.
 * 
 * @author GRONOWSKI Stephane svan001@aol.com
 * 
 *         igsat 2010
 * 
 */
public class CNFUseXMLHandler extends XMLHandler {

	private CNFUseXMLStatus		status	= CNFUseXMLStatus.NONE;
	private CNFUse				cnfuse	= null;
	private CNF					cnf		= null;

	private SolverFactory		solfactory;
	private PreProcessorFactory	prefactory;
	private SessionBlock		first	= null;
	private File				directory;


	public CNFUseXMLHandler(SessionBlock first, PreProcessorFactory prefactory, SolverFactory solFactory, File directory) {
		solfactory = solFactory;
		this.prefactory = prefactory;
		this.first = first;
		this.directory = directory;
	}

	@Override
	public boolean characters2(char[] ch, int start, int length) throws SAXException {
		if (status == CNFUseXMLStatus.STATUS)
		{
			super.characters2(ch, start, length);
			return true;
		}
		else
			throw new SAXException("unnexpecte behavior");
	}

	@Override
	public boolean endDocument2() throws SAXException {
		return false;
	}

	@Override
	public boolean endElement2(String uri, String localName, String qName) throws SAXException {
		switch (status) {
		case NONE:
			return false;

		case SESSION_BLOCK:
			if (qName.equals(XMLBaliseFormat.SESSION_BLOCK))
			{// ferme session block
				status = CNFUseXMLStatus.NONE;
				Long time = ((SessionBlockXMLHandler) delegate).getPreviousTime();
				if (time == null)
					throw new SAXException("problem PREVIOUS TIME");
				cnfuse.setPreviousExecutionTime(time);
				delegate = null;

				return true;
			}
			throw new SAXException("end of CNF was expected");

		case CNF:
			if (qName.equals(XMLBaliseFormat.CNF))
			{// ferme cnf
				status = CNFUseXMLStatus.NONE;
				cnf = ((CNFXMLHandler) delegate).getCnf();
				if (cnf == null)
					throw new SAXException("problem CNF");
				delegate = null;

				// cree cnfuse
				if (first != null)
					cnfuse = new CNFUse(first, cnf);
				else
					cnfuse = new CNFUse(cnf);
				return true;
			}
			throw new SAXException("end of CNF was expected");

		case STATUS:
			if (qName.equals(XMLBaliseFormat.CNFUSE_STATUS))
			{// ferme status
				status = CNFUseXMLStatus.NONE;
				setStatus();
				return true;
			}
			throw new SAXException("end of CNF was expected");


		case SOLVER_EXECUTION:
			if (qName.equals(XMLBaliseFormat.SOLVER_EXECUTION))
			{// ferme solver
				status = CNFUseXMLStatus.NONE;
				SolverExecutionBlock block = ((SolverExecutionXMLHandler) delegate).getSolverBlock();
				if (block == null)
					throw new SAXException("problem with SOLVER BLOCK");
				delegate = null;

				block.setCnf(cnf);
				cnfuse.addSolver(block);
				return true;
			}
			throw new SAXException("end of SOLVER EXECUTION was expected");

		case PREPROC_EXECUTION:
			if (qName.equals(XMLBaliseFormat.PREPROC_CNFUSE))
			{// ferme preproc
				status = CNFUseXMLStatus.NONE;
				PreprocessorExecutionBlock block = ((PreProcCNFUseXMLHandler) delegate).getBlock();
				CNFUse tmp = ((PreProcCNFUseXMLHandler) delegate).getCnfuse();
				if (block == null || tmp == null)
					throw new SAXException("problem with PREPROC CNFUSE BLOCK");
				delegate = null;

				block.setCnf(cnf);
				cnfuse.addPreproc(block, tmp);
				return true;
			}
			throw new SAXException("end of PREPROC CNFUSE BLOCK was expected");

		}

		// attend une fin de balise qui existe pas...
		throw new SAXException("an other end of element was expected");
	}

	@Override
	public boolean startElement2(String arg0, String arg1, String arg2, Attributes arg3) throws SAXException {
		if (status != CNFUseXMLStatus.NONE)
			throw new SAXException("already have a started element");

		if (arg2.equals(XMLBaliseFormat.SESSION_BLOCK))
		{// balise session block
			if (cnf == null)
				throw new SAXException("can't get session block : don't have a CNF");

			// set les donnees pour recupere le session block
			status = CNFUseXMLStatus.SESSION_BLOCK;
			delegate = new SessionBlockXMLHandler();

			return true;
		}

		if (arg2.equals(XMLBaliseFormat.CNFUSE_STATUS))
		{// balise staus
			if (cnf == null)
				throw new SAXException("can't get status : don't have a CNF");

			// set les donnees pour recupere le session block
			status = CNFUseXMLStatus.STATUS;
			return true;
		}

		if (arg2.equals(XMLBaliseFormat.CNF))
		{// balise cnf
			if (cnf != null)
				throw new SAXException("already have a CNF");

			// set les donnees pour recupere la cnf
			status = CNFUseXMLStatus.CNF;
			delegate = new CNFXMLHandler(directory);

			return true;
		}

		if (arg2.equals(XMLBaliseFormat.SOLVER_EXECUTION))
		{// balise solver exec
			if (cnf == null)
				throw new SAXException("can't get solver execution : don't have a CNF");

			// set les donnees pour recupere le solver
			status = CNFUseXMLStatus.SOLVER_EXECUTION;
			delegate = new SolverExecutionXMLHandler(cnfuse.getFirst(), solfactory);

			return true;
		}

		if (arg2.equals(XMLBaliseFormat.PREPROC_CNFUSE))
		{// balise preproc cnfuse
			if (cnf == null)
				throw new SAXException("can't get preprocessor : don't have a CNF");

			// set les donnees pour recupere le preproc
			status = CNFUseXMLStatus.PREPROC_EXECUTION;
			delegate = new PreProcCNFUseXMLHandler(cnfuse.getFirst(), prefactory, solfactory, directory);

			return true;
		}
		// peut pas commencer balise qui existe pas
		throw new SAXException("unexpected balise: " + arg2);
	}

	/**
	 * Return the cnfuse.
	 * 
	 * @return the cnfuse
	 */
	public CNFUse getCnfuse() {
		return cnfuse;
	}

	/**
	 * Set the status in the {@link CNFUse}.
	 * 
	 * @throws SAXException
	 */
	private void setStatus() throws SAXException {
		cnfuse.setStatus(CNFUseStatus.getValueFromXML(buffer.toString()));
		if (cnfuse.getStatus() == null)
			throw new SAXException("status unknown");
	}

}
